home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / audio / drive / libsample.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  26.2 KB  |  1,164 lines

  1. /*
  2.  * Copyright 1992-1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  *    libsample -
  19.  *        read and write samples of sound.
  20.  *
  21.  *    exports:
  22.  *        sample *readsample(name);
  23.  *         writesample(s,name);
  24.  *
  25.  *        printsample(s);
  26.  *
  27.  *        playsample(s);
  28.  *        playsubsample(s,start,finish);
  29.  *        flushsample();
  30.  *
  31.  *        expandsample(s);
  32.  *        minmaxsample(s,min,max);
  33.  *        scalesample(s,gain);
  34.  *        stereoizesample(s,mag);
  35.  *
  36.  *        freesample(s);
  37.  *        sample *clonesample(s);
  38.  *
  39.  *        sample *tonesample(nsamples);
  40.  *        sample *subsample(s,begin,end);
  41.  *        sample *extendsample(s,len);
  42.  *        reversesample(s);
  43.  *
  44.  *        beginnotes();
  45.  *        playnote(s,ftime,amplitude);
  46.  *        endnotes();
  47.  *        setbpm(b)
  48.  *        flushnotes(ftime)
  49.  *        sethumanize(time,amp)
  50.  *
  51.  *            Paul Haeberli - 1991
  52.  * ANSI-fied by Howard Look
  53.  */
  54. #include "math.h"
  55. #include "stdio.h"
  56. #include "fcntl.h"
  57. #include "sys/types.h"
  58. #include "malloc.h"
  59. #include "aiff.h"
  60. #include "audio.h"
  61. #include "sample.h"
  62.  
  63. int hack_sginap(long ticks)
  64. {
  65.     return sginap(ticks);
  66. }
  67.  
  68. int ilimit(min,v,max)
  69. int min,v,max;
  70. {
  71.     if(v<min)
  72.     return min;
  73.     if(v>max)
  74.     return max;
  75.     return v;
  76. }
  77.  
  78. /*
  79.  *    code to READ an aiff file
  80.  *
  81.  *
  82.  */
  83. static void
  84. copy_audio_samps(ssnd_chunk_t *ssnd_data, 
  85.                 audio_params_t *audio_params,
  86.                 sample *s);
  87.  
  88. typedef union 
  89. {
  90.     unsigned char b[2];
  91.     short         s;
  92. } align_short_t;
  93.  
  94. typedef union 
  95. {
  96.     unsigned char b[4];
  97.     long         l;
  98. } align_long_t;
  99.  
  100. /*
  101.  * local subroutines
  102.  */
  103. void parse_cmd_line(int argc, char **argv);
  104. static int  read_chunk_header(chunk_header_t *);
  105. static void read_form_chunk(chunk_header_t *, form_chunk_t *);
  106. static void read_comm_chunk(chunk_header_t *,comm_chunk_t *, 
  107.                       audio_params_t *audio_params);
  108. static void read_ssnd_chunk(chunk_header_t *, ssnd_chunk_t *);
  109. static void skip_chunk(chunk_header_t *);
  110.  
  111. /*
  112.  * globals 
  113.  */
  114. static const char *filename;     /* input file name */
  115. static int fd;            /* input file descriptor */
  116. static char *myname;       /* name of this program */
  117. static long bytes_per_samp;
  118. static long samps_per_frame;
  119. static long frames_per_sec;
  120. static long total_frames;
  121. static long total_samps;
  122. static long total_samp_bytes;
  123. static long total_bytes;     /* total bytes in output file */
  124.  
  125. sample *readsample(const char *name)
  126. {
  127.     int i,n;
  128.     char buf[8];
  129.     chunk_header_t chunk_header;
  130.     form_chunk_t form_data;
  131.     comm_chunk_t comm_data;
  132.     ssnd_chunk_t ssnd_data;
  133.     audio_params_t audio_params;
  134.     ALport audio_port;
  135.     sample *s;
  136.     
  137.     myname = "readaiff";
  138.     filename = name;
  139.  
  140.     if ((fd = open(filename, O_RDONLY)) < 0) {
  141.         fprintf(stderr, "%s: couldn't open %s\n", myname, filename);
  142.         exit(-1);
  143.     }
  144.  
  145.     if ((n = read_chunk_header(&chunk_header)) != CHUNK_HEADER) {
  146.         fprintf(stderr, "%s: failed to read FORM chunk header\n", myname);
  147.         exit(-1);
  148.     }
  149.     if (strncmp(chunk_header.id, "FORM", 4)) {        /* form container */
  150.         fprintf(stderr, "%s: couldn't find FORM chunk id\n", myname);
  151.         exit(-1);
  152.     }
  153.     read_form_chunk(&chunk_header, &form_data);
  154.  
  155.     /*
  156.      * loop on the local chunks
  157.      */
  158.     while (1) {
  159.         if ((n = read_chunk_header(&chunk_header)) == 0)
  160.             goto loop_done;
  161.         else if (n != CHUNK_HEADER) {
  162.             fprintf(stderr, "%s: failed to read a chunk header\n", myname);
  163.             exit(-1);
  164.         }
  165.         if (!strncmp(chunk_header.id, "COMM", 4))    /* common */
  166.             read_comm_chunk(&chunk_header, &comm_data, &audio_params);
  167.         else if (!strncmp(chunk_header.id, "SSND", 4))  /* sound data */
  168.             read_ssnd_chunk(&chunk_header, &ssnd_data);
  169.         else if ((!strncmp(chunk_header.id, "MARK", 4))  /* marker */
  170.               || (!strncmp(chunk_header.id, "INST", 4))  /* instrument */
  171.               || (!strncmp(chunk_header.id, "APPL", 4))   /* appl specific */
  172.               || (!strncmp(chunk_header.id, "MIDI", 4))  /* midi data */
  173.               || (!strncmp(chunk_header.id, "AESD", 4))   /* audio  rec */
  174.               || (!strncmp(chunk_header.id, "COMT", 4))   /* comments */
  175.               || (!strncmp(chunk_header.id, "NAME", 4))   /* text */
  176.               || (!strncmp(chunk_header.id, "AUTH", 4))   /* text */
  177.               || (!strncmp(chunk_header.id, "(c) ", 4))   /* text */
  178.               || (!strncmp(chunk_header.id, "ANNO", 4))) {   /* text */
  179.             skip_chunk(&chunk_header);
  180.         } else {
  181.             fprintf(stderr,
  182.             "%s: bad chunk id  0x%02x%02x%02x%02x\n",
  183.                      myname, chunk_header.id[0],chunk_header.id[1],
  184.                      chunk_header.id[2], chunk_header.id[3]);
  185.         }
  186.     } /* while */
  187.  
  188. loop_done:
  189.  
  190.     s = (sample *)malloc(sizeof(struct sample));
  191.     /*
  192.      * save the sample data
  193.      */
  194.     s->samprate = audio_params.samprate;
  195.     s->sampwidth = audio_params.sampwidth;
  196.     s->nchannels = audio_params.nchannels;
  197.     if(s->sampwidth != 2) {
  198.     fprintf(stderr,"samplewidth must be 2 bytes for now\n");
  199.     exit(1);
  200.     }
  201.     if(s->nchannels != 2) {
  202.     fprintf(stderr,"nchannels must be 2 (stereo) for now\n");
  203.     exit(1);
  204.     }
  205.     copy_audio_samps(&ssnd_data, &audio_params, s);
  206.     close(fd);
  207.     return s;
  208. }
  209.  
  210. /*
  211.  * R E A D _ C H U N K _ H E A D E R
  212.  */
  213. static int
  214. read_chunk_header(chunk_header_t *chunk_header)
  215. {
  216.     align_long_t align_long;
  217.     char buf[CHUNK_HEADER];
  218.     int i, n;
  219.  
  220.     if ((n = read(fd, buf, CHUNK_HEADER)) != CHUNK_HEADER)
  221.         return(n);
  222.     for (i=0; i<4; i++)
  223.         chunk_header->id[i] = buf[i];
  224.     for (i=0; i<4; i++)
  225.         align_long.b[i] = buf[i+4];
  226.     chunk_header->size = align_long.l;
  227.     return(CHUNK_HEADER);
  228. }
  229.  
  230. static void
  231. read_form_chunk(chunk_header_t *chunk_header, form_chunk_t *form_data)
  232. {
  233.     int n;
  234.     char buf[FORM_CHUNK_DATA];
  235.  
  236.     if (chunk_header->size < 0) {
  237.         fprintf(stderr, "%s: invalid FORM chunk data size %d\n",myname,
  238.                                  chunk_header->size);
  239.         exit(-1);
  240.     } else if (chunk_header->size == 0) {
  241.         fprintf(stderr,"%s: FORM chunk data size = 0\n", myname);
  242.         exit(0);
  243.     }
  244.     if ((n = read(fd, buf, FORM_CHUNK_DATA)) != FORM_CHUNK_DATA) {
  245.         fprintf(stderr, "%s: couldn't read AIFF identifier from %s\n",
  246.                            myname, filename);
  247.         exit(-1);
  248.     }
  249.     if (strncmp(buf, "AIFF", 4)) {
  250.        fprintf(stderr, "%s: %s does not have an AIFF identifier\n",
  251.                   myname, filename);
  252.        exit(-1);
  253.     }
  254. }
  255.  
  256.  
  257. /*
  258.  * R E A D _ C O M M _ C H U N K
  259.  */
  260. static void
  261. read_comm_chunk(chunk_header_t *chunk_header, 
  262.                     comm_chunk_t *comm_data,
  263.                     audio_params_t *audio_params)
  264. {
  265.     int n;
  266.     char *buf, *bufp;
  267.     int i;
  268.     align_short_t align_short;
  269.     align_long_t  align_long;
  270.  
  271.     buf = malloc(COMM_CHUNK_DATA + 1); /* one extra loc at the end */
  272.  
  273.     if ((n = read(fd,  buf, COMM_CHUNK_DATA)) != COMM_CHUNK_DATA) {
  274.         fprintf(stderr, 
  275.         "%s: failed to read COMM chunk data. Expected %d bytes, got %d.\n",
  276.             myname, COMM_CHUNK_DATA, n); 
  277.         exit(-1);
  278.     }
  279.     bufp = buf;
  280.     for (i=0; i<2; i++)
  281.        align_short.b[i] = *bufp++;
  282.     comm_data->nchannels = align_short.s;
  283.     for (i=0; i<4; i++) 
  284.        align_long.b[i]  = *bufp++;
  285.     comm_data->nsampframes = align_long.l;
  286.     for (i=0; i<2; i++)
  287.        align_short.b[i] = *bufp++;
  288.     comm_data->sampwidth = align_short.s; 
  289.     /*
  290.      * the sample rate value from the common chunk is an 80-bit IEEE extended
  291.      * floating point number:
  292.      * [s bit] [15 exp bits (bias=16383)] [64 mant bits (leading 1 not hidden)]
  293.      *
  294.      * turns out we can just grab bytes 2 and 3 (if bytes numbered 0 ... 9)
  295.      * and cast them as an integer: the integer value equals the sample rate
  296.      */
  297.     for (i=0; i<2; i++)
  298.         bufp++;
  299.     align_short.b[0] = *bufp++;
  300.     align_short.b[1] = *bufp++;
  301.     for (i=0; i<6; i++)
  302.         bufp++;
  303.     comm_data->samprate = (unsigned short)align_short.s;
  304.  
  305.     switch (comm_data->samprate) {
  306.         case 48000:
  307.         audio_params->samprate = AL_RATE_48000;        
  308.         break;
  309.     case 44100:
  310.         audio_params->samprate = AL_RATE_44100;
  311.         break;
  312.     case 32000:
  313.         audio_params->samprate = AL_RATE_32000;
  314.         break;
  315.     case 16000:
  316.         audio_params->samprate = AL_RATE_16000;
  317.         break;
  318.     case  8000:
  319.         audio_params->samprate = AL_RATE_8000;
  320.         break;
  321.         default:
  322.                 fprintf(stderr,"%s: can't set output sample rate to %d\n",
  323.                             myname, audio_params->samprate);
  324.         audio_params->samprate = AL_RATE_48000;        
  325.     }
  326.     switch (comm_data->nchannels) {
  327.     case 1:
  328.         audio_params->nchannels = AL_MONO;
  329.         break;
  330.     case 2:
  331.         audio_params->nchannels = AL_STEREO;
  332.         break;
  333.     default:
  334.         fprintf(stderr, "%s: can't handle %d channels per frame\n",
  335.                     myname, comm_data->nchannels);
  336.         audio_params->nchannels = AL_STEREO;
  337.     }
  338.     switch (comm_data->sampwidth) {
  339.     case 8:
  340.          audio_params->sampwidth = AL_SAMPLE_8;
  341.         break;
  342.     case 16:
  343.          audio_params->sampwidth = AL_SAMPLE_16;
  344.         break;
  345.     case 24:
  346.          audio_params->sampwidth = AL_SAMPLE_24;
  347.         break;
  348.     default:
  349.         fprintf(stderr, "%s: unsupported sample width %d bits\n",
  350.             myname, comm_data->nchannels);
  351.          audio_params->sampwidth = AL_SAMPLE_16;
  352.     }
  353.     free(buf);
  354. }
  355.  
  356. static void 
  357. read_ssnd_chunk(chunk_header_t *chunk_header, ssnd_chunk_t *ssnd_data)
  358. {
  359.     char buf[SSND_CHUNK_DATA];
  360.     int i;
  361.     align_long_t align_long;
  362.  
  363.     read(fd, buf, SSND_CHUNK_DATA);
  364.     for (i=0; i<4; i++) 
  365.         align_long.b[i] = buf[i];
  366.     ssnd_data->offset = align_long.l;
  367.     for (i=0; i<4; i++)
  368.         align_long.b[i] = buf[i+4];
  369.     ssnd_data->blocksize = align_long.l;
  370.     /*
  371.      * store the offset to the beginning of the audio sample data so that
  372.      * we can come back and play it later
  373.      */ 
  374.     ssnd_data->file_position = lseek(fd, 0, SEEK_CUR);
  375.     ssnd_data->sample_bytes = chunk_header->size - 2*sizeof(long);
  376.  
  377.     /*
  378.      * move the fileptr to the end of the chunk
  379.      */
  380.     lseek(fd, ssnd_data->sample_bytes, SEEK_CUR);
  381. }
  382.  
  383.  
  384. /*
  385.  * COPY_AUDIO_SAMPS
  386.  */
  387. static void
  388. copy_audio_samps(ssnd_chunk_t *ssnd_data, 
  389.                 audio_params_t *audio_params,
  390.                 sample *s)
  391. {
  392.     int num_bufs;
  393.     int leftover_bytes;
  394.     int leftover_samps;
  395.     int leftover_frames;
  396.     int nread;
  397.     int bytes_per_buf;
  398.     int samps_per_buf;
  399.     int samp_count;
  400.     int frame_count;
  401.     int frames_per_buf;
  402.     float secs_per_frame;
  403.     float secs_per_buf;
  404.     float sec_count;
  405.     int i;
  406.     char *sampbuf;
  407.    
  408.     /*
  409.      * decide what size blocks of samples we should read from the
  410.      * AIFF file and pass to ALwritesamps
  411.      */
  412.     switch (audio_params->sampwidth) {
  413.         case AL_SAMPLE_8: 
  414.         bytes_per_samp = 1; 
  415.         break;
  416.         case AL_SAMPLE_16: 
  417.         default:
  418.         bytes_per_samp = 2; 
  419.         break;
  420.     }
  421.     switch (audio_params->nchannels) {
  422.         case AL_MONO: 
  423.         samps_per_frame = 1; 
  424.         break;
  425.         case AL_STEREO: 
  426.         default:
  427.         samps_per_frame = 2; 
  428.         break;
  429.     }
  430.     switch(audio_params->samprate) {
  431.         case AL_RATE_48000: frames_per_sec = 48000; break;
  432.         case AL_RATE_44100: frames_per_sec = 44100; break;
  433.         case AL_RATE_32000: frames_per_sec = 32000; break;
  434.     case AL_RATE_16000: frames_per_sec = 16000; break; 
  435.     case AL_RATE_8000:  frames_per_sec =  8000; break;
  436.     }
  437.     /*
  438.      * make the buffer large enough to hold 1/2 sec of audio frames
  439.      */
  440.     secs_per_frame = 1.0 / ((float)frames_per_sec);
  441.     bytes_per_buf  = bytes_per_samp * samps_per_frame * frames_per_sec / 2;
  442.     samps_per_buf  = bytes_per_buf / bytes_per_samp;
  443.     frames_per_buf = samps_per_buf / samps_per_frame;
  444.     secs_per_buf   = secs_per_frame * frames_per_buf;
  445.     sampbuf = malloc(bytes_per_buf); 
  446.  
  447.     /*
  448.      * figure out how many reads we have to do
  449.      */
  450.     total_samp_bytes = ssnd_data->sample_bytes;
  451.     total_samps      = total_samp_bytes / bytes_per_samp;
  452.     total_frames     = total_samps / samps_per_frame;
  453.     num_bufs         = total_samp_bytes / bytes_per_buf;
  454.     leftover_bytes   = total_samp_bytes % bytes_per_buf;
  455.     leftover_samps   = leftover_bytes / bytes_per_samp;
  456.     leftover_frames  = leftover_samps / samps_per_frame;
  457.  
  458.     /*
  459.      * move the fileptr to the beginning of the sample data
  460.      */
  461.     lseek(fd, ssnd_data->file_position, SEEK_SET);
  462.     s->nsamples = total_samps;
  463.     s->data = (short *)malloc(total_samp_bytes);
  464.     read(fd, s->data, total_samp_bytes);
  465. }
  466.  
  467. /*
  468.  * S K I P _ C H U N K
  469.  */
  470. static void
  471. skip_chunk(chunk_header_t *chunk_header)
  472. {
  473.     lseek(fd, chunk_header->size, SEEK_CUR);
  474. }
  475.  
  476. /*
  477.  *    Stuff to WRITE an aiff file
  478.  *
  479.  */
  480.  
  481. /*
  482.  * local subroutines
  483.  */
  484. static void write_form_chunk(form_chunk_t *);
  485. static void write_comm_chunk(comm_chunk_t *, sample *);
  486. static void write_ssnd_chunk(ssnd_chunk_t *);
  487. static void write_audio(sample *s);
  488. static void update_form_chunk(form_chunk_t *);
  489. static void update_comm_chunk(comm_chunk_t *);
  490. static void update_ssnd_chunk(ssnd_chunk_t *);
  491.  
  492. void writesample(sample *s, char *name)
  493. {
  494.     int i,n;
  495.     form_chunk_t form_chunk;
  496.     comm_chunk_t comm_chunk;
  497.     ssnd_chunk_t ssnd_chunk;
  498.     
  499.     myname = "writesample";
  500.     filename = name;
  501.     if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) {
  502.     fprintf(stderr, "%s: couldn't open %s\n", myname, filename);
  503.     exit(-1);
  504.     }
  505.     write_form_chunk(&form_chunk);
  506.     write_comm_chunk(&comm_chunk, s);
  507.     write_ssnd_chunk(&ssnd_chunk);
  508.     write_audio(s);
  509.     total_bytes = FORM_CHUNK + COMM_CHUNK + SSND_CHUNK + total_samp_bytes;
  510.     update_form_chunk(&form_chunk);
  511.     update_comm_chunk(&comm_chunk);
  512.     update_ssnd_chunk(&ssnd_chunk);
  513.     close(fd);
  514. }
  515.  
  516. /*
  517.  * W R I T E _ F O R M _ C H U N K
  518.  */
  519. static void
  520. write_form_chunk(form_chunk_t *form_chunk)
  521. {
  522.     char buf[FORM_CHUNK];
  523.  
  524.     bzero(buf,FORM_CHUNK);
  525.     bcopy("FORM",buf,4);
  526.     bcopy("AIFF",buf+8,4);
  527.     write(fd,buf,FORM_CHUNK);
  528.     form_chunk->file_position = 0;
  529. }
  530.  
  531. /*
  532.  * W R I T E _ C O M M _ C H U N K 
  533.  */
  534. static void
  535. write_comm_chunk(comm_chunk_t *comm_chunk, sample *s)
  536. {
  537.     char buf[COMM_CHUNK];
  538.     int i;
  539.     char *bufp, *cp;
  540.     long tmplong;
  541.     short tmpshort;
  542.  
  543. /*
  544.  *    here is the structure of a COMM_CHUNK:
  545.  *        
  546.  *    0    char[4]        const "COMM"
  547.  *    4    long        const COMM_CHUNK_DATA
  548.  *    8    short        n channels
  549.  *    10    long         n sample frames
  550.  *    14    short         sample width
  551.  *    16    char[10]    80 bit floating point sample rate
  552.  */
  553.     bzero(buf,COMM_CHUNK);
  554.     bcopy("COMM",buf,4);             /* char[4] chunk id */
  555.     tmplong =  COMM_CHUNK_DATA;
  556.     bcopy(&tmplong,buf+4,sizeof(long));     /* long COMM_CHUNK_DATA */
  557.     tmpshort = s->nchannels;
  558.     bcopy(&tmpshort,buf+8,sizeof(short));     /* short nchannels */
  559.     tmplong = 0;    /* gets written later */
  560.     bcopy(&tmplong,buf+10,sizeof(long));     /* long sampleframes (later) */
  561.     tmpshort = 8*s->sampwidth;
  562.     bcopy(&tmpshort,buf+14,sizeof(short));     /* short sampwidth */
  563.     tmpshort = s->samprate;
  564.     cp = (char *)&tmpshort;             /* 10-bit extended samprate*/
  565.     bufp = buf+16;
  566.     /* 
  567.      * WOW!! this works: 80 bit floating point number follows 
  568.      */
  569.     *bufp++ =  0x40;
  570.     *bufp++ =  0x0e;
  571.     *bufp++ =  *cp++;
  572.     *bufp++ =  *cp;
  573.     /* the rest is already zero!! */
  574.  
  575.     comm_chunk->file_position = lseek(fd, 0, SEEK_CUR);
  576.     write(fd, buf, COMM_CHUNK);
  577. }
  578.  
  579. /*
  580.  * W R I T E _ S S N D _ C H U N K 
  581.  */
  582. static void
  583. write_ssnd_chunk(ssnd_chunk_t *ssnd_chunk)
  584. {
  585.     char buf[SSND_CHUNK];
  586.  
  587.     bzero(buf,SSND_CHUNK);
  588.     bcopy("SSND",buf,4);
  589.     ssnd_chunk->file_position = lseek(fd, 0, SEEK_CUR);
  590.     write(fd, buf, SSND_CHUNK);
  591. }
  592.  
  593. /*
  594.  *     save_audio
  595.  */
  596. static void
  597. write_audio(sample *s)
  598. {
  599.     int nbytes;
  600.     unsigned char *buf;
  601.     int samps_per_buf;
  602.     int bytes_per_buf;
  603.     int frames_per_buf;
  604.     int frames_per_sec;
  605.     int bytes_per_samp;
  606.     int samps_per_frame;
  607.     int togo, thistime;
  608.  
  609.     bytes_per_samp  = 2;  /* hardwire to 16-bit samples */
  610.     samps_per_frame = 2;  /* hardwire to stereo */
  611.     frames_per_sec  = ((float)s->samprate); 
  612.     frames_per_buf  = frames_per_sec / 2;
  613.     samps_per_buf   = frames_per_buf * samps_per_frame;
  614.     bytes_per_buf   = samps_per_buf * bytes_per_samp;
  615.     total_frames = 0;
  616.     total_samp_bytes = 0;
  617.     
  618.     /*
  619.      * we assume the file pointer now points to the beginning
  620.      * of the audio sample section of the AIFF file
  621.      */ 
  622.     togo = s->nsamples*s->sampwidth;
  623.     buf = (unsigned char *)s->data;
  624.     while(togo) {
  625.     thistime = bytes_per_buf;
  626.     if(thistime>togo)
  627.         thistime = togo;
  628.     if ((nbytes = write(fd, buf, thistime)) != thistime) {
  629.           fprintf(stderr,
  630.           "%s:  tried to write %d bytes to %s, actually wrote %d\n",
  631.            myname, thistime, filename, nbytes);
  632.         exit(1);
  633.     }
  634.     buf += thistime;
  635.         total_frames += (nbytes/(samps_per_frame*bytes_per_samp));
  636.         total_samp_bytes += nbytes;
  637.     togo -= thistime;
  638.     }
  639. }
  640.  
  641. /*
  642.  * U P D A T E _ F O R M _ C H U N K
  643.  */
  644. static void
  645. update_form_chunk(form_chunk_t *form_chunk)
  646. {
  647.     long seekpos;
  648.  
  649.     seekpos = form_chunk->file_position + 4;    /* seek past 4 id bytes */
  650.     lseek(fd, seekpos, SEEK_SET);
  651.     writelong(fd,total_bytes-CHUNK_HEADER);
  652. }
  653.  
  654. /*
  655.  * U P D A T E _ C O M M _ C H U N K
  656.  */
  657. static void 
  658. update_comm_chunk(comm_chunk_t *comm_chunk)
  659. {
  660.     long seekpos;
  661.  
  662.     seekpos = comm_chunk->file_position + CHUNK_HEADER + sizeof(short);
  663.     lseek(fd, seekpos, SEEK_SET);      
  664.     writelong(fd,total_frames);
  665.  
  666. }
  667.  
  668. /*
  669.  * U P D A T E _ S S N D _ C H U N K
  670.  */
  671. static void 
  672. update_ssnd_chunk(ssnd_chunk_t *ssnd_chunk)
  673. {
  674.     long seekpos;
  675.  
  676.     seekpos = ssnd_chunk->file_position + CHUNK_ID;
  677.     lseek(fd, seekpos, SEEK_SET);
  678.     writelong(fd,SSND_CHUNK_DATA + total_samp_bytes);
  679. }
  680.  
  681. writelong(fd,val)
  682. int fd;
  683. long val;
  684. {
  685.     write(fd, &val, sizeof(long));
  686. }
  687.  
  688. /*
  689.  *    ulitity functions follow
  690.  *
  691.  */
  692. static int firsted;
  693. static ALport audioport;
  694.  
  695. static writeaudio(data,nshorts,samprate)
  696. short *data;
  697. int nshorts, samprate;
  698. {
  699.     long pvbuf[2];
  700.     ALconfig portconfig;
  701.  
  702.     if(!firsted) {
  703.     pvbuf[0] = AL_OUTPUT_RATE;
  704.     pvbuf[1] = samprate;
  705.     ALsetparams(AL_DEFAULT_DEVICE,pvbuf,2);
  706.     portconfig = ALnewconfig();
  707.     ALsetwidth(portconfig,2);
  708.     ALsetchannels(portconfig,2);
  709.     audioport = ALopenport("name","w",portconfig);
  710.     firsted = 1;
  711.     }
  712.     if(!nshorts)
  713.     return;
  714.     ALwritesamps(audioport,data,nshorts);
  715. }
  716.  
  717. void playsample(sample *s)
  718. {
  719.     playsubsample(s,0,s->nsamples-1);
  720. }
  721.  
  722. void playsubsample(sample *s,int start, int finish)
  723. {
  724.     start = ilimit(0,start,s->nsamples-1);
  725.     finish = ilimit(0,finish,s->nsamples-1);
  726.     start &= 0xffffffe;
  727.     finish &= 0xffffffe;
  728.     writeaudio(s->data+start,finish-start+1,s->samprate);
  729. }
  730.  
  731. void flushsample(void)
  732. {
  733.     if(firsted) {
  734.     while(ALgetfilled(audioport) > 0)
  735.         sginap(1);
  736.     }
  737. }
  738.  
  739. void printsample(sample *s)
  740. {
  741.     int min, max;
  742.  
  743.     printf("\nsample rate: %d\n",s->samprate);
  744.     printf(" n channels: %d\n",s->nchannels);
  745.     printf(" samp width: %d\n",s->sampwidth);
  746.     printf(" n samples : %d\n",s->nsamples);
  747.     minmaxsample(s,&min,&max);
  748.     printf(" min val: %d\n",min);
  749.     printf(" max val: %d\n",max);
  750. }
  751.  
  752. void expandsample(sample *s)
  753. {
  754.     int min, max, del;
  755.     int n;
  756.     short *sptr;
  757.  
  758.     minmaxsample(s,&min,&max);
  759.     if(min<0)
  760.        min = -min;
  761.     if(min>max)
  762.     max = min;
  763.     del = 2*max;
  764.     min = -max;
  765.  
  766.     if(del == 0)
  767.     return;
  768.     sptr = s->data;
  769.     n = s->nsamples;
  770.     while(n--) {
  771.     *sptr = ((((unsigned long)(*sptr-min))*64000)/del)-32000;
  772.      sptr++;
  773.     }
  774. }
  775.  
  776. float rmssample(s)
  777. sample *s;
  778. {
  779. }
  780.  
  781. minmaxsample(s,min,max)
  782. sample *s;
  783. int *min, *max;
  784. {
  785.     int n, smin, smax;
  786.     short *sptr;
  787.      
  788.     sptr = s->data;
  789.     n = s->nsamples;
  790.     smin = 40000;
  791.     smax = -40000;
  792.     while(n--) {
  793.     if(*sptr>smax)
  794.         smax = *sptr;
  795.     if(*sptr<smin)
  796.         smin = *sptr;
  797.     sptr++;
  798.     }
  799.     *min = smin;
  800.     *max = smax;
  801. }
  802.  
  803. scalesample(s,gain)
  804. sample *s;
  805. float gain;
  806. {
  807.     int val, n;
  808.     short *sptr;
  809.      
  810.     sptr = s->data;
  811.     n = s->nsamples;
  812.     while(n--) {
  813.     val = (*sptr * gain)+0.5;
  814.     if(val<-32000)
  815.         val = -32000;
  816.     if(val>32000)
  817.         val = 32000;
  818.     *sptr++ = val;
  819.     }
  820. }
  821.  
  822. float flerp();
  823.  
  824. stereoizesample(s,mag)
  825. sample *s;
  826. float mag;
  827. {
  828.     int nsamples;
  829.     int nframes;
  830.     float r, l, m;
  831.     short *sptr;
  832.  
  833.     nframes = s->nsamples/2;
  834.     sptr = s->data;
  835.     while(nframes--) {
  836.        r = sptr[0];
  837.        l = sptr[1];
  838.        m = (r+l)/2.0;
  839.        r = flerp(m,r,mag);
  840.        l = flerp(m,l,mag);
  841.        if(r<-32768) r = -32768;
  842.        if(r> 32767) r = 32767;
  843.        if(l<-32768) l = -32768;
  844.        if(l> 32767) l = 32767;
  845.        sptr[0] = r;
  846.        sptr[1] = l;
  847.        sptr+=2;
  848.     }
  849. }
  850.  
  851. void freesample(sample *s)
  852. {
  853.     free(s->data);
  854.     free(s);
  855. }
  856.  
  857. sample *clonesample(s)
  858. sample *s;
  859. {
  860.     sample *cs;
  861.  
  862.     cs = (sample *)malloc(sizeof(struct sample));
  863.     *cs = *s;
  864.     cs->data = (short *)malloc(s->nsamples*sizeof(short));
  865.     bcopy(s->data,cs->data,s->nsamples*sizeof(short));
  866.     return cs;
  867. }
  868.  
  869. sample *tonesample(nsamples)
  870. int nsamples;
  871. {
  872.     sample *s;
  873.     short *sptr, val;
  874.     int i, frames;
  875.  
  876.     if(nsamples&1)
  877.        nsamples--;
  878.     s = (sample *)malloc(sizeof(struct sample));
  879.     s->samprate = 32000;
  880.     s->nchannels = 2;
  881.     s->sampwidth = 2;
  882.     s->nsamples = nsamples;
  883.     s->data = (short *)malloc(s->nsamples*sizeof(short));
  884.     sptr = s->data;
  885.     frames = nsamples/2;
  886.     for(i=0; i<frames; i++) {
  887.     val = 32000.0*sin(2.0*M_PI*i/frames);
  888.     *sptr++ = val;
  889.     *sptr++ = val;
  890.     }
  891.     return s;
  892. }
  893.  
  894. sample *subsample(s,begin,end)
  895. sample *s;
  896. int begin, end;
  897. {
  898.     int temp, len;
  899.     sample *cs;
  900.  
  901.     begin = ilimit(0,begin,s->nsamples-1);
  902.     end = ilimit(0,end,s->nsamples-1);
  903.     begin &= 0xffffffe;
  904.     end &= 0xffffffe;
  905.     if(end<begin) {
  906.     temp = end;
  907.     end = begin;
  908.     begin = temp;
  909.     }
  910.     len = end-begin+1;
  911.     cs = (sample *)malloc(sizeof(struct sample));
  912.     *cs = *s;
  913.     cs->nsamples = len;
  914.     cs->data = (short *)malloc(len*sizeof(short));
  915.     bcopy(s->data+begin,cs->data,len*sizeof(short));
  916.     return cs;
  917. }
  918.  
  919. sample *extendsample(s,len) 
  920. sample *s;
  921. int len;
  922. {
  923.     sample *cs;
  924.  
  925.     cs = (sample *)malloc(sizeof(struct sample));
  926.     *cs = *s;
  927.     cs->nsamples = len;
  928.     cs->data = (short *)malloc(len*sizeof(short));
  929.     bzero(cs->data,len*sizeof(short));
  930.     if(s->nsamples<len)
  931.        len = s->nsamples;
  932.     bcopy(s->data,cs->data,len*sizeof(short));
  933.     return cs;
  934. }
  935.  
  936. reversesample(s) 
  937. sample *s;
  938. {
  939.     int i, nframes;
  940.     short *sptr, *dptr, t;
  941.  
  942.     nframes = s->nsamples/s->nchannels;
  943.     sptr = s->data;
  944.     dptr = s->data+s->nchannels*nframes;
  945.     while(sptr<dptr) {
  946.     dptr -= s->nchannels;
  947.     for(i=0; i<s->nchannels; i++) {
  948.         t = sptr[i];
  949.         sptr[i] = dptr[i];
  950.         dptr[i] = t;
  951.     }
  952.     sptr += s->nchannels;
  953.     }
  954.  
  955. }
  956.  
  957. sample *addsample(s1,s2,offset)
  958. sample *s1, *s2;
  959. int offset;
  960. {
  961. #ifdef NOTDEF
  962.     int nsamples;
  963.     int min, max
  964.     sample *as;
  965.     short *aptr, *bptr, *sptr;
  966.     short p1, p2, s;
  967.     short v1, v2, s;
  968.  
  969.     if(offset<0) {
  970.     min = 0;
  971.     } else {
  972.     min = offset;
  973.     }
  974.     max = MAX(s1->nsamples,s2->nsamples+offset);
  975.     nsamples = max-min;
  976.     as = (sample *)malloc(sizeof(struct sample));
  977.     *as = *s1;
  978.     as->nsamples = nsamples;
  979.     as->data = (short *)malloc(nsamples*sizeof(short));
  980.     for(i=min; i<max; i++) {
  981.     p1 = 
  982.     if(i<0
  983.     a = s1
  984.     }
  985. #endif
  986. }
  987.  
  988. /* XXX graphic equalizer someday*/
  989.  
  990. /* 
  991.  *    support for playing simultaneous notes follows 
  992.  *
  993.  */
  994. dprintf()
  995. {
  996. }
  997.  
  998. static int curtime = 0;
  999.  
  1000. typedef struct activesample {
  1001.     struct activesample *next;
  1002.     sample *s;
  1003.     int tmin;
  1004.     int tmax;
  1005.     float amplitude;
  1006. } activesample;
  1007.  
  1008. #define CHUNKSIZE    (100)
  1009. #define FOREVER        (1000000000)
  1010.  
  1011. static activesample *active;
  1012. static float *fbuf;
  1013. static short *sbuf;
  1014. static float bpm = 120.0;
  1015. static float humanamp = 0.0;
  1016. static float humantime = 0.0;
  1017.  
  1018. beginnotes()
  1019. {
  1020.     curtime = 0;
  1021.     active = 0;
  1022. }
  1023.  
  1024. endnotes()
  1025. {
  1026.     flushnotes(1000000.0);
  1027.     flushsample();
  1028. }
  1029.  
  1030. setbpm(b)
  1031. float b;
  1032. {
  1033.     bpm = b;
  1034. }
  1035.  
  1036. sethumanize(t,a)
  1037. float t, a;
  1038. {
  1039.     humantime = t;
  1040.     humanamp = a;
  1041. }
  1042.  
  1043. float frand();
  1044.  
  1045. playnote(s,ftime,amplitude)
  1046. sample *s;
  1047. float ftime;
  1048. float amplitude;
  1049. {
  1050.     activesample *as;
  1051.     int time;
  1052.  
  1053.     ftime = ftime+(humantime*(frand()-0.5));
  1054.     time = ftime*(60.0/bpm)*s->samprate;
  1055.     if(time<0.0)
  1056.     time = 0.0;
  1057.     if(time<curtime) {
  1058.     fprintf(stderr,"putsample: start times must be increasing\n");
  1059.     fprintf(stderr,"time is %d, curtime is %d\n",time,curtime);
  1060.     return;
  1061.     }
  1062.     as = (activesample *)malloc(sizeof(activesample));
  1063.     as->s = s;
  1064.     as->tmin = time;
  1065.     as->tmax = time+(s->nsamples/2);
  1066.     as->amplitude = amplitude*(1.0-humanamp*frand());
  1067.  
  1068. /* add the sample to the active list */
  1069.     as->next = active;
  1070.     active = as;
  1071. }
  1072.  
  1073. flushnotes(ftime)
  1074. float ftime;
  1075. {
  1076.     int time;
  1077.     activesample *as, *temp;
  1078.     int mint, nplay, thistime, n;
  1079.     int div, val;
  1080.     short *sptr;
  1081.     float *fptr;
  1082.     float amp;
  1083.  
  1084.     if(!active)
  1085.     return;
  1086.     time = ftime*(60.0/bpm)*active->s->samprate;
  1087.     time -= CHUNKSIZE;    /* XXXXX */
  1088.     if(!sbuf) {
  1089.     fbuf = (float *)malloc(2*CHUNKSIZE*sizeof(float));
  1090.     sbuf = (short *)malloc(2*CHUNKSIZE*sizeof(short));
  1091.     }
  1092. dprintf("A curtime %d\n",curtime);
  1093.     while(active && curtime<time) {
  1094.  
  1095. /* figure out how many samples we can put out before change in samples  */
  1096.     mint = FOREVER;
  1097.     as = active;
  1098.     while(as) {
  1099.         if(curtime<as->tmin) {
  1100.         if(mint>as->tmin)
  1101.             mint = as->tmin;
  1102.         } else if(curtime<as->tmax) {
  1103.         if(mint>as->tmax)
  1104.             mint = as->tmax;
  1105.         }
  1106.         as = as->next;
  1107.     }
  1108.     nplay = mint - curtime;
  1109.     if(nplay>CHUNKSIZE)
  1110.         nplay = CHUNKSIZE;
  1111.  
  1112. /* clear the accumulator */
  1113.     bzero(fbuf,2*nplay*sizeof(float));
  1114.  
  1115. /* accumulate the active samples */
  1116.     div = 0;
  1117.     as = active;
  1118.     while(as) {
  1119.         if((as->tmin<curtime+nplay) && (as->tmax>curtime)) {
  1120.         fptr = fbuf;
  1121.         sptr = as->s->data+2*(curtime-as->tmin);
  1122.         amp = as->amplitude;
  1123.         n = 2*nplay;
  1124.         while(n--) {
  1125.             *fptr = *fptr + amp*(*sptr++);
  1126.             fptr++;
  1127.         }
  1128.         div++;
  1129.         }
  1130.         as = as->next;
  1131.     }
  1132.  
  1133. /* copy and range check */
  1134.     fptr = fbuf;
  1135.     sptr = sbuf;
  1136.     n = 2*nplay;
  1137.     while(n--) {
  1138.         val = *fptr++;
  1139.         if(val<-32000)
  1140.         *sptr++ = -32000;
  1141.         else if(val>32000)
  1142.         *sptr++ = 32000;
  1143.         else
  1144.         *sptr++ = val;
  1145.     }
  1146.  
  1147. /* play the sum of the active samples */
  1148.     writeaudio(sbuf,2*nplay,active->s->samprate);
  1149.  
  1150. /* update the time */
  1151.     curtime += nplay;
  1152.  
  1153. /* remove old samples */
  1154.     for( as = (activesample *)&active; as->next; )  {
  1155.         if (as->next->tmax <= curtime) {
  1156.         temp = as->next;
  1157.         as->next = temp->next;
  1158.         free(temp);
  1159.         } else
  1160.         as = as->next;
  1161.     }
  1162.     }
  1163. }
  1164.